Skip to content

Module Architecture

flowchart TD
    SUB["sadeem_subscription\nSubscription Base"]
    PORT["sadeem_portainer\nPortainer"]
    CF["sadeem_cloudflare\nCloudflare"]

    S["sadeem.subscription (inherit)\nDocker type · image · ports\nstack compose generation"]
    ST["sadeem.subscription.stage (inherit)\nper-stage Docker stack\ndatabase · volumes · ports"]
    ENV["sadeem.portainer.environment (inherit)\nsubscription count per environment"]
    IMGTAG["sadeem.portainer.image.tag (inherit)\nDocker image version tags"]
    UPD["sadeem.subscription.update.request (inherit)\nDocker-specific resource upgrade"]

    SUB --> S
    PORT --> S
    CF --> S

    S --> ST
    S --> ENV
    S --> UPD

    ST --> SK1([action_portainer_create_stack\ngenerate compose → deploy via Portainer])
    ST --> SK2([action_docker_stack_update\nredeploy stack with new config])
    ST --> SK3([action_restart_docker\nrestart container])
    ST --> SK4([action_docker_log\nstream container logs])
    ST --> SK5([action_docker_run_cmd\nexec command in container])
    ST --> SK6([action_docker_cp_subscription_addons\ncopy addons into running stack])
    ST --> SK7([action_cancel_docker\nstop and remove Docker stack])

    S --> CS1([action_create_code_server\ndeploy VS Code container])
    S --> CS2([action_start_code_server\nstart VS Code container])
    S --> CS3([action_stop_code_server\nstop VS Code container])
    S --> CS4([action_remove_code_server\nremove VS Code container])

    S --> PM1([action_confirm override\nauto-assign HTTP + WebSocket ports])
    IMGTAG --> PM2([get_best_environment\npick Docker host by capacity])

    EXT[/Portainer API\nstack and container CRUD/]
    SK1 --> EXT
    SK2 --> EXT
    SK4 --> EXT
    SK5 --> EXT

Module Description

Adds the Docker deployment strategy to the Sadeem SAAS platform. Each subscription is deployed as an isolated Docker stack via Portainer with its own Odoo instance and database.

Feature Description
Docker Subscriptions Deploy as isolated Docker stacks; configurable workers, memory limits, ports, volumes, server-wide modules
Docker Stages Each stage (dev/test/prod) gets its own independent stack, database, and configuration
Stack Lifecycle Create, update, start, stop, cancel stacks from the subscription or stage form
Container Control Restart containers, view live logs, run commands, copy addons into running stacks
Code Server Deploy a browser-based VS Code container per stage for remote development
Port Management Auto-assign HTTP and WebSocket ports per subscription to avoid conflicts
Dashboard Extension Adds Environments panel showing live container capacity across all Portainer environments
Update Requests Extends resource upgrade workflow to handle Docker-specific limits (workers, memory)

Dependencies

  • sadeem_cloudflare
  • sadeem_subscription
  • product
  • sadeem_portainer

Menus

This module does not add new menu items. It extends the subscription and stage forms with Docker-specific tabs and actions.

Subscription Type

This module adds the docker selection value to saas_subscription_type. When selected, subscriptions are provisioned as isolated Docker stacks managed through Portainer.

Key Fields

Subscription — Docker additions (sadeem.subscription inherit)

Field Type Description
saas_subscription_type Selection Extended with ('docker', 'Docker') value
docker_image Many2one Portainer image config to use for this subscription
docker_image_environment Many2one Portainer environment the stack runs in
stack_id Integer Portainer stack ID (set after deployment)
docker_worker_count Integer Number of Odoo worker processes
docker_limit_time_cpu Integer CPU time limit per request in seconds (default: 60)
docker_limit_time_real Integer Real time limit per request (default: 120)
docker_limit_time_real_cron Integer Real time limit for cron jobs (default: 0 = unlimited)
docker_limit_requests Integer Max requests per worker before restart (default: 8192)
docker_log_level Selection Odoo log level: info, debug, warning, critical
docker_server_wide_modules Char Comma-separated server-wide Odoo modules
docker_server_auto_install_modules Char Modules to install automatically on container start
docker_update_module Char Module to update on next stack redeploy
docker_without_demo Boolean Disable demo data (default: True)
docker_sendfile Boolean Enable X-Sendfile for static file serving
docker_postgresql_server_external Boolean Use external PostgreSQL server
docker_postgresql_server_id Many2one External PostgreSQL server config
docker_user_addons Char Path to user addons directory
docker_log Text Latest container log output
docker_latest_log_tail Integer Number of log lines to fetch (max 1000)
docker_cmd / docker_cmd_output Char / Text Command to execute in container and its output
code_server_stack_id Integer Portainer stack ID for the VS Code container

Stage — Docker additions (sadeem.subscription.stage inherit)

Field Type Description
stack_id Integer Per-stage Portainer stack ID
stack_created Boolean Whether the stack has been deployed at least once
docker_postgresql_server_external Boolean External PostgreSQL override per stage
docker_postgresql_server_id Many2one External PostgreSQL server for this stage
docker_server_wide_modules Char Server-wide module override per stage

Lifecycle & States

The Docker module uses the same subscription and stage states defined in sadeem_subscription. Key Docker-specific behaviors:

  • Port assignment at confirm: action_confirm override auto-assigns http_port and websocket_port by calling get_best_environment() on the image; raises UserError if no environment is available.
  • Stack creation: action_portainer_create_stack builds the Docker Compose string and deploys via Portainer API; both subscription and stage have this action.
  • Stack redeployment: action_docker_stack_update regenerates the compose and updates the running stack.
  • Cancellation: action_cancel stops and removes the Portainer stack before marking the subscription/stage cancelled.

Key Actions

Action Model Description
action_confirm (override) sadeem.subscription Assigns HTTP/WebSocket ports; selects best Portainer environment
action_run_subscription (override) sadeem.subscription Calls action_portainer_create_stack to deploy the main Odoo stack
action_portainer_create_stack sadeem.subscription / stage Generates Docker Compose YAML and deploys via Portainer API
action_docker_stack_update sadeem.subscription / stage Regenerates compose config and redeploys existing stack
action_restart_docker sadeem.subscription / stage Restarts the Odoo container via Portainer exec
action_stop_docker sadeem.subscription / stage Stops the container
action_start_docker sadeem.subscription / stage Starts a stopped container
action_docker_log sadeem.subscription / stage Fetches container logs from Portainer
action_docker_run_cmd sadeem.subscription / stage Executes a shell command in the container (safety-checked)
action_docker_cp_subscription_addons sadeem.subscription / stage Copies addon files into the running container
action_cancel (override) sadeem.subscription / stage Stops and removes the Portainer stack before cancelling
action_create_code_server (override) sadeem.subscription Deploys VS Code browser container as a separate Portainer stack
action_start/stop/remove_code_server (override) sadeem.subscription Manages the VS Code container lifecycle

Warnings & Important Notes

  • HTTP port required: action_run_subscription raises UserError if http_port is 0 — happens if the subscription was not confirmed properly. Reset to draft and confirm again.
  • No environment available: action_confirm raises UserError if docker_image has no available/configured environment.
  • Log tail limit: Fetching more than 1000 lines raises UserError.
  • Command safety check: action_docker_run_cmd passes commands through is_safe_command() in sadeem_saas_docker/utils/utils.py; raises UserError for disallowed commands.
  • Stack creation failure: action_portainer_create_stack raises ValidationError with the Portainer error message on failure.
  • Code server stack: The VS Code container is deployed as a separate Portainer stack; code_server_stack_id tracks it independently from stack_id.